; haribote-os boot asm
; TAB=4

BOTPAK	EQU		0x00280000		; Bootpack的加载目标
DSKCAC	EQU		0x00100000		; 磁盘缓存位置
DSKCAC0	EQU		0x00008000		; 磁盘缓存位置（实模式）

; BOOT_INFO关系
CYLS	EQU		0x0ff0			; 由引导扇区设置
LEDS	EQU		0x0ff1
VMODE	EQU		0x0ff2			; 有关颜色数量的信息。有多少位颜色？
SCRNX	EQU		0x0ff4			; 分辨率x
SCRNY	EQU		0x0ff6			; 分辨率Y
VRAM	EQU		0x0ff8			; 图形缓冲区的起始地址

		ORG		0xc200			; 该程序的加载位置

; 设置屏幕模式

		MOV		AL,0x13			; VGA图形，320x200x8bit彩色
		MOV		AH,0x00
		INT		0x10
		MOV		BYTE [VMODE],8	; 记下屏幕模式（由C语言引用）
		MOV		WORD [SCRNX],320
		MOV		WORD [SCRNY],200
		MOV		DWORD [VRAM],0x000a0000

; 要求BIOS告诉您键盘的LED状态

		MOV		AH,0x02
		INT		0x16 			; keyboard BIOS
		MOV		[LEDS],AL

; 防止PIC接受任何中断
; 在AT兼容机器规格中，如果要初始化PIC，
; 有时，如果我在CLI之前不这样做，则挂起
; 稍后初始化PIC

		MOV		AL,0xff
		OUT		0x21,AL
		NOP						; 如果继续执行OUT命令，似乎无法使用该模型
		OUT		0xa1,AL

		CLI						; 此外，中断在CPU级别被禁用

; 设置A20GATE，以便CPU可以访问1MB或更大的内存

		CALL	waitkbdout
		MOV		AL,0xd1
		OUT		0x64,AL
		CALL	waitkbdout
		MOV		AL,0xdf			; enable A20
		OUT		0x60,AL
		CALL	waitkbdout

; 进入保护模式

[INSTRSET "i486p"]				; 我最多要使用486条指令的说明

		LGDT	[GDTR0]			; 设置临时GDT
		MOV		EAX,CR0
		AND		EAX,0x7fffffff	; 将bit31设置为0（以防止分页）
		OR		EAX,0x00000001	; 将bit0设置为1（进入保护模式）
		MOV		CR0,EAX
		JMP		pipelineflush
pipelineflush:
		MOV		AX,1*8			;  读写段32bit
		MOV		DS,AX
		MOV		ES,AX
		MOV		FS,AX
		MOV		GS,AX
		MOV		SS,AX

; 引导程序包传输

		MOV		ESI,bootpack	; 转移源
		MOV		EDI,BOTPAK		; 转发目的地
		MOV		ECX,512*1024/4
		CALL	memcpy

; 顺便盘数据也向原来的位置传送

; 首先从引导扇区

		MOV		ESI,0x7c00		; 转移源
		MOV		EDI,DSKCAC		; 转发目的地
		MOV		ECX,512/4
		CALL	memcpy

; 剩下的全部

		MOV		ESI,DSKCAC0+512	; 转移源
		MOV		EDI,DSKCAC+512	; 转发目的地
		MOV		ECX,0
		MOV		CL,BYTE [CYLS]
		IMUL	ECX,512*18*2/4	; 气缸数转换成字节数/4
		SUB		ECX,512/4		; 只减去IPL的部分
		CALL	memcpy

; 我已经做了所有与asmhead相关的工作，
;	让bootpack完成其余的工作

; bootpack引导

		MOV		EBX,BOTPAK
		MOV		ECX,[EBX+16]
		ADD		ECX,3			; ECX += 3;
		SHR		ECX,2			; ECX /= 4;
		JZ		skip			; 没有什么可以转移的
		MOV		ESI,[EBX+20]	; 转移源
		ADD		ESI,EBX
		MOV		EDI,[EBX+12]	; 转发目的地
		CALL	memcpy
skip:
		MOV		ESP,[EBX+12]	; 初始堆栈值
		JMP		DWORD 2*8:0x0000001b

waitkbdout:
		IN		 AL,0x64
		AND		 AL,0x02
		JNZ		waitkbdout		; 如果AND的结果不为0，请转到waitkbdout
		RET

memcpy:
		MOV		EAX,[ESI]
		ADD		ESI,4
		MOV		[EDI],EAX
		ADD		EDI,4
		SUB		ECX,1
		JNZ		memcpy			; 如果减法的结果不为0，请转到memcpy
		RET
; 只要您不忘记输入地址大小前缀，可以使用字符串指令编写memcpy

		ALIGNB	16
GDT0:
		RESB	8				; 空选择器
		DW		0xffff,0x0000,0x9200,0x00cf	; 读写段32bit
		DW		0xffff,0x0000,0x9a28,0x0047	; 可执行段32bit（用于bootpack）

		DW		0
GDTR0:
		DW		8*3-1
		DD		GDT0

		ALIGNB	16
bootpack:
